package org.egedede.gravity.ui.desktop.swing;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Point;
import java.util.Collection;
import java.util.Observable;

import org.egedede.gravity.model.Body;
import org.egedede.gravity.model.GravityModel;
import org.egedede.simulation.model.Simulation;
import org.egedede.simulation.model.impl.TimingEndCondition;
import org.egedede.simulation.ui.desktop.swing.SimulationView;
import org.egedede.utils.ui.CoordinateTransformer;

// TODO: Auto-generated Javadoc
/**
 * The Class GravitySystem2DView.
 */
public class GravitySystem2DView extends SimulationView {

	/** The Constant serialVersionUID. */
	private static final long serialVersionUID = 1724784357256523789L;

	/** The simulation. */
	private Simulation simulation;

	/** The transformer. */
	private CoordinateTransformer transformer;

	/** indicate if speed should be shown */
	private boolean showSpeed = true;
	/** indicate if acceleration should be shown */
	private boolean showAcceleration = true;
	
	/**bodies width*/
	private int bodiesWidth = 6;
	/**
	 * Instantiates a new gravity system2 d view.
	 */
	public GravitySystem2DView() {
		super();
		transformer = new CoordinateTransformer();

	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see javax.swing.JComponent#paintComponent(java.awt.Graphics)
	 */
	@Override
	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		g.drawString("Hello : (" + getWidth() + ", " + getHeight() + ")", 10,
				10);
		g.drawString("transformer : (" + this.transformer.getX() + ", " +this.transformer.getY() + "| " +this.transformer.getScaleX() + ", " +this.transformer.getScaleY() + ")", 30,
				30);
		g.drawString("iteration : (" + ((TimingEndCondition)this.simulation.getEndConditions().iterator().next()).getCounter()+")", 30,
				50);
		GravityModel model = (GravityModel) this.simulation.getModel();
		Collection<Body> bodies = model.getSystem().getBodies();
		Color oldColor = g.getColor();
		g.setColor(Color.BLACK);
		int i = 2;
		for (Body body : bodies) {
			Point pointToDraw = this.transformer.transform(new Point(body.getX(),
					body.getY()), new Point(getWidth() / 2, getHeight() / 2));
			this.bodiesWidth = body.getMass()/10;
			g.drawArc(pointToDraw.x-this.bodiesWidth/2, pointToDraw.y-this.bodiesWidth/2, this.bodiesWidth, this.bodiesWidth, 0, 360);
			g.drawString(body.getLabel(),pointToDraw.x+5, pointToDraw.y-10);
			if(this.showSpeed){
				g.setColor(Color.BLUE);
				g.drawLine(pointToDraw.x, pointToDraw.y, pointToDraw.x+body.getVx(), pointToDraw.y+body.getVy());
			}
			if(this.showAcceleration){
				g.setColor(Color.RED);
				g.drawLine(pointToDraw.x, pointToDraw.y, pointToDraw.x+body.getAx(), pointToDraw.y+body.getAy());
			}
			i++;
			g.setColor(Color.BLACK);
			g.drawString(body.getLabel() + " (" + body.getX() + ", "
					+ body.getY() + ") => (" + pointToDraw.x + ", "
					+ pointToDraw.y + ")", 10, 10 + (20 * i));
		}
		g.setColor(oldColor);
	}

	/**
	 * (non-Javadoc)
	 * 
	 * @see java.util.Observer#update(java.util.Observable, java.lang.Object)
	 */
	@Override
	public void update(Observable o, Object arg) {
		updateReferential();
		this.repaint();

	}

	/**
	 * uthe different data needed to display : center, scale, etc...
	 */
	private void updateReferential() {
		// TODO Auto-generated method stub
		// mettre à jour le transformer.
		GravityModel model = (GravityModel) simulation.getModel();
		Collection<Body> bodies = model.getSystem().getBodies();
		// contains the sum of coordinates then the baricenter 
		int x = 0;
		int y = 0;
		float scaleX = 0;
		float scaleY = 0;
		int minX = 0, maxX = 0;
		int minY = 0, maxY = 0;
		for (Body body : bodies) {
			int bodyX = body.getX();
			int bodyY = body.getY();
			if (bodyX < minX)
				minX = bodyX;
			if (bodyX > maxX)
				maxX = bodyX;
			if (bodyY < minY)
				minY = bodyY;
			if (bodyY > maxY)
				maxY = bodyY;
			x += bodyX;
			y += bodyY;
		}
		long border = 10;
		// update the scale of the transformer
		float diffX = getWidth() - 2 * border > (maxX - minX) ? getWidth() - 2
				* border : (maxX - minX);
		float diffY = getHeight() - 2 * border > (maxY - minY) ? getHeight()
				- 2 * border : (maxX - minX);
		scaleX = (this.getWidth() - 2 * border) / diffX;
		scaleY = (this.getHeight() - 2 * border) / diffY;
		this.transformer.setScaleX(scaleX);
		this.transformer.setScaleY(scaleY);
		// update the position of the transformer
		x = -x / bodies.size();
		y = -y / bodies.size();
		this.transformer.setX(x);
		this.transformer.setY(y);
		this.transformer.setBorder(border);
	}

	/**
	 * Sets the simulation.
	 * 
	 * @param simulation
	 *            the new simulation
	 */
	public void setSimulation(Simulation simulation) {
		this.simulation = simulation;
	}

}
